package com.java2207.group1.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.java2207.group1.bo.AssetsBo;
import com.java2207.group1.bo.ExpenditureBo;
import com.java2207.group1.bo.IncomeBo;
import com.java2207.group1.bo.MonthBo;
import com.java2207.group1.common.LayuiPageVo;
import com.java2207.group1.mapper.AssetsMapper;
import com.java2207.group1.mapper.ExpenditureMapper;
import com.java2207.group1.mapper.IncomeMapper;
import com.java2207.group1.pojo.Assets;
import com.java2207.group1.pojo.Expenditure;
import com.java2207.group1.pojo.Income;
import com.java2207.group1.service.FinancialManagementService;
import com.java2207.group1.util.DateUtil;
import com.java2207.group1.util.DealNumber;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author HuiCL
 * @version 1.0
 * @date 2022/7/25 18:00
 */
@Service("/financialManagementService")
public class FinancialManagementServiceImpl implements FinancialManagementService {
    @Autowired
    private AssetsMapper assetsMapper;

    @Autowired
    private ExpenditureMapper expenditureMapper;

    @Autowired
    private IncomeMapper incomeMapper;

    //----------------------------------收入表income------------------------------------------------------//
    @Override
    public int addIncome(Income income) {
        int i = incomeMapper.addRevenue(income);
        updateAssetsOfDate(income.getIncomeDate(), income.getAmountOfIncome());
        return i;
    }

    @Override
    public int updateIncome(Income income) {

        return incomeMapper.updateRevenue(income);
    }

    @Override
    public int deleteIncomeById(int id) {
        return incomeMapper.deleteRevenueById(id);
    }

    @Override
    public int batchRemoveIncome(List<Integer> list) {
        return incomeMapper.batchRemoveIncome(list);
    }


    @Override
    public LayuiPageVo<Income> incomePageData(Map<String, Object> params) {
        // mybatis 的 分页插件
        Integer page = Integer.parseInt(params.get("page") + "");
        Integer limit = Integer.parseInt(params.get("limit") + "");

        PageHelper.startPage(page, limit);
        List<Income> incomeList = incomeMapper.revenuePageData(params);

        // mybatis 的 分页数据结构
        PageInfo<Income> incomePageInfo = new PageInfo<>(incomeList);

        //把mybatis 的 分页数据 封装到  layui 的分页数据结构中
        LayuiPageVo<Income> incomeLayuiPageVo = new LayuiPageVo<>();

        incomeLayuiPageVo.setCode(0);  // layui 默认 0 是正确的状态码
        incomeLayuiPageVo.setMsg("分页列表数据"); // 提示信息
        incomeLayuiPageVo.setCount(incomePageInfo.getTotal()); // 总记录数
        incomeLayuiPageVo.setData(incomePageInfo.getList());  // 分页的列表数据

        return incomeLayuiPageVo;
    }

    @Override
    public List<IncomeBo> incomeExcelData(Income income) {

        List<Income> incomeList = incomeMapper.selectDataThatMeetConditions(income);

        List<IncomeBo> commodityBos = incomeList.stream()
                .map((eachIncome) -> {
                    IncomeBo incomeBo = new IncomeBo();
                    incomeBo.setId(eachIncome.getId());
                    incomeBo.setPayingClients(eachIncome.getPayingClients());
                    incomeBo.setContactClients(eachIncome.getContactClients());
                    incomeBo.setAmountOfIncome(eachIncome.getAmountOfIncome());
                    incomeBo.setIncomeDate(eachIncome.getIncomeDate());
                    return incomeBo;
                }).collect(Collectors.toList());
        return commodityBos;
    }

    //-----------------------------资产支出表expenditure----------------------------------------------------------//
    @Override
    public int addExpenditure(Expenditure expenditure) {
        int i = expenditureMapper.addExpenditure(expenditure);
        updateAssetsOfDate(expenditure.getDisbursementDate(), -(expenditure.getExpenseAmount()));
        return i;
    }

    @Override
    public int updateExpenditure(Expenditure expenditure) {
        return expenditureMapper.updateExpenditure(expenditure);
    }

    @Override
    public int deleteExpenditureById(int id) {
        return expenditureMapper.deleteExpenditureById(id);
    }

    @Override
    public int batchRemoveExpenditure(List<Integer> list) {
        return expenditureMapper.batchRemoveExpenditure(list);
    }

    @Override
    public LayuiPageVo<Expenditure> expenditurePageData(Map<String, Object> params) {
        // mybatis 的 分页插件
        Integer page = Integer.parseInt(params.get("page") + "");
        Integer limit = Integer.parseInt(params.get("limit") + "");

        PageHelper.startPage(page, limit);
        List<Expenditure> expenditureList = expenditureMapper.expenditurePageData(params);

        // mybatis 的 分页数据结构
        PageInfo<Expenditure> expenditurePageInfo = new PageInfo<>(expenditureList);

        //把mybatis 的 分页数据 封装到  layui 的分页数据结构中
        LayuiPageVo<Expenditure> expenditureLayuiPageVo = new LayuiPageVo<>();

        expenditureLayuiPageVo.setCode(0);  // layui 默认 0 是正确的状态码
        expenditureLayuiPageVo.setMsg("分页列表数据"); // 提示信息
        expenditureLayuiPageVo.setCount(expenditurePageInfo.getTotal()); // 总记录数
        expenditureLayuiPageVo.setData(expenditurePageInfo.getList());  // 分页的列表数据

        return expenditureLayuiPageVo;
    }

    @Override
    public List<ExpenditureBo> expenditureExcelData(Expenditure expenditure) {

        List<Expenditure> expenditureList = expenditureMapper.selectDataThatMeetConditions(expenditure);

        List<ExpenditureBo> expenditureBoList = expenditureList.stream()
                .map((eachExpenditure) -> {
                    ExpenditureBo expenditureBo = new ExpenditureBo();
                    expenditureBo.setId(eachExpenditure.getId());
                    expenditureBo.setPayor(eachExpenditure.getPayor());
                    expenditureBo.setContactPayor(eachExpenditure.getContactPayor());
                    expenditureBo.setUseOfAssets(eachExpenditure.getUseOfAssets());
                    expenditureBo.setExpenseAmount(eachExpenditure.getExpenseAmount());
                    expenditureBo.setDisbursementDate(eachExpenditure.getDisbursementDate());
                    return expenditureBo;
                }).collect(Collectors.toList());
        return expenditureBoList;
    }


    //-----------------------------总资产表assets-----------------------------------------//
    @Override
    public int addAssets(Assets assets) {
        // 查询用户所要插入的日期, 是否已经存在数据
        Assets outOfDateAssets = assetsMapper.selectAssetsOfDate(DateUtil.dateToStr(assets.getDate(), "yyyy-MM-dd"));
        int i = -1;
        if (outOfDateAssets == null) { // 如果不存在数据
            i = assetsMapper.addAssets(assets);
        } else { // 如果已存在数据
            assets.setId(outOfDateAssets.getId());
            i = updateAssets(assets);
        }

        return i;
    }

    @Override
    public int updateAssets(Assets assets) {
        // 用户要将数据修改为[某个日期], 先查询要修改为的 该[某个日期] 是否存在已存在
        Assets outOfDateAssets = assetsMapper.selectAssetsOfDate(DateUtil.dateToStr(assets.getDate(), "yyyy-MM-dd"));

        // 如果不存在, 直接修改即可
        // 如果 该[某个日期] 存在, 将 已存在的该[某个日期] 的数据删掉, 然后再修改后即可

        // 但是有可能用户并未修改日期,
        // 这意味着, 若删除 该[某个日期], 那么用户sql语句的 ...... where id = ? 就可能报错(因为该id的数据已被删除)
        // 所以需要判断 用户想修改 { 该[某个日期]的id 与 where id = ? 的id }是否相等, 相等的话, 直接修改即可
        // 不相等的话, 先删除 旧有的[某个日期] 的数据, 再修改即可
        if (outOfDateAssets != null) { // 防止空指针异常, 所以这里if判断
            if (!outOfDateAssets.getId().equals(assets.getId())) {
                assetsMapper.deleteAssetsById(outOfDateAssets.getId());
            }
        }

        return assetsMapper.updateAssets(assets);
    }

    @Override
    public int deleteAssetsById(int id) {
        return assetsMapper.deleteAssetsById(id);
    }

    /**
     * 查询指定日期的资产数据
     *
     * @param date
     * @return
     */
    @Override
    public Assets selectAssetsOfDate(Date date) {
        return assetsMapper.selectAssetsOfDate(DateUtil.dateToStr(date, "yyyy-MM-dd"));
    }

    /**
     * 实时更新指定日期的资产, 应紧跟在添加资金收入与资金支出方法之后
     *
     * @return
     */
    @Override
    public int updateAssetsOfDate(Date date, int money) {
        int i = -1;
        Assets assets = assetsMapper.profitOfDate(DateUtil.dateToStr(date, "yyyy-MM-dd"));
        // 如果查询不到该日期有任何盈亏记录
        if (assets == null) {
            // 在Mysql查询时, 使用了ifnull()函数令null的字段为0, 所以理论上来说, assets不会为null
            System.out.println("今日未曾有盈亏!");
        } else {// 如果该日期有盈亏记录
            // 查询Assets表的该日期的数据
            Assets outdatedAssetsData = assetsMapper.selectAssetsOfDate(DateUtil.dateToStr(date, "yyyy-MM-dd"));

            if (outdatedAssetsData == null) {// 但还未曾记录该日期的资产状态
                Assets lastDataOfAssets = assetsMapper.selectLastDataBefore(DateUtil.dateToStr(date, "yyyy-MM-dd"));
                assets.setTotalAssets(assets.getTodayProfit() + lastDataOfAssets.getTotalAssets());
                assets.setDate(date);
                // 在今日插入一条资产状态数据
                i = assetsMapper.addAssets(assets);
                return i;
            }
            assets.setId(outdatedAssetsData.getId());
            assets.setTotalAssets(outdatedAssetsData.getTotalAssets() + money);
            assets.setDate(date);

            i = assetsMapper.updateAssets(assets);

        }

        return i;
    }

    @Override
    public LayuiPageVo<Assets> assetsPageData(Map<String, Object> params) {
        // mybatis 的 分页插件
        Integer page = Integer.parseInt(params.get("page") + "");
        Integer limit = Integer.parseInt(params.get("limit") + "");

        PageHelper.startPage(page, limit);
        List<Assets> assetsList = assetsMapper.assetsPageData(params);

        // mybatis 的 分页数据结构
        PageInfo<Assets> assetsPageInfo = new PageInfo<>(assetsList);

        //把mybatis 的 分页数据 封装到  layui 的分页数据结构中
        LayuiPageVo<Assets> assetsLayuiPageVo = new LayuiPageVo<>();

        assetsLayuiPageVo.setCode(0);  // layui 默认 0 是正确的状态码
        assetsLayuiPageVo.setMsg("分页列表数据"); // 提示信息
        assetsLayuiPageVo.setCount(assetsPageInfo.getTotal()); // 总记录数
        assetsLayuiPageVo.setData(assetsPageInfo.getList());  // 分页的列表数据

        return assetsLayuiPageVo;
    }

    @Override
    public List<AssetsBo> assetsExcelData(Assets assets) {

        List<Assets> assetsList = assetsMapper.selectDataThatMeetConditions(assets);

        List<AssetsBo> assetsBoList = assetsList.stream()
                .map((eachAssets) -> {
                    AssetsBo assetsBo = new AssetsBo();
                    assetsBo.setId(eachAssets.getId());
                    assetsBo.setTodayIncome(eachAssets.getTodayIncome());
                    assetsBo.setTodayExpense(eachAssets.getTodayExpense());
                    assetsBo.setTodayProfit(eachAssets.getTodayProfit());
                    assetsBo.setTotalAssets(eachAssets.getTotalAssets());
                    assetsBo.setDate(eachAssets.getDate());
                    return assetsBo;
                }).collect(Collectors.toList());
        return assetsBoList;
    }

    /**
     * 从assets表中 查询指定年份的财务报告(即一年内每月的月收入与月支出)
     * @param year
     * @return
     */
    @Override
    public List<MonthBo> yearlyFinancialStatements(String year) {
        List<MonthBo> monthBoList = assetsMapper.queryIncomeAndExpenditureFromYear(year);

        List<MonthBo> financialStatements = new ArrayList<>();
        for (int i = 0; i < 12; i++) {
            financialStatements.add(i, new MonthBo(i + 1, 0, 0));
        }

        monthBoList.forEach((eachMonth) -> {
            financialStatements.get(eachMonth.getEveryMonth() - 1).setSumOfIncome(eachMonth.getSumOfIncome());
            financialStatements.get(eachMonth.getEveryMonth() - 1).setSumOfExpenditure(eachMonth.getSumOfExpenditure());
        });

        return financialStatements;
    }


    /**
     * 该方法已经过时, 已被废弃
     * 从income和expenditure表中 查询指定年份的财务报告(即一年内每月的月收入与月支出)
     * @param year
     * @return
     */
    @Override
    @Deprecated
    public List<MonthBo> yearlyFinancialStatementsFromIncomeAndExpenditure(String year) {
        List<MonthBo> incomeFromYear = incomeMapper.queryIncomeFromYear(year);
        List<MonthBo> expenditureFromYear = expenditureMapper.queryExpenditureFromYear(year);

        List<MonthBo> monthBoList = new ArrayList<>();
        for (int i = 0; i < 12; i++) {
            monthBoList.add(i, new MonthBo(i + 1, 0, 0));
        }

        incomeFromYear.forEach((monthlyIncome) -> {
            monthBoList.get(monthlyIncome.getEveryMonth() - 1).setSumOfIncome(monthlyIncome.getSumOfIncome());
        });

        expenditureFromYear.forEach((monthlyExpenditure) -> {
            monthBoList.get(monthlyExpenditure.getEveryMonth() - 1).setSumOfExpenditure(monthlyExpenditure.getSumOfExpenditure());
        });

        return monthBoList;
    }

    @Override
    public int batchRemoveAssets(List<Integer> list) {
        return assetsMapper.batchRemoveAssets(list);
    }

    /**
     * 得到一年内 所有月盈利与月支出数据中的 最大值的某个近似值, 该近似值用来作为统计图的Y轴的最大值
     * 例如, 109会被近似为200, 1548会被近似为2000, 3981会被近似为4000
     * @param monthBoList
     * @return 一年中 所有月收入与月盈利数据中 最大值的某个近似值
     */
    public int maximumForYAxis(List<MonthBo> monthBoList) {
        MonthBo monthBoOfMaxIncome = monthBoList.stream().max(Comparator.comparing(MonthBo::getSumOfIncome)).get();
        MonthBo monthBoOfMaxExpenditure = monthBoList.stream().max(Comparator.comparing(MonthBo::getSumOfExpenditure)).get();
        return DealNumber.numberForYAxis(Math.max(monthBoOfMaxIncome.getSumOfIncome(), monthBoOfMaxExpenditure.getSumOfExpenditure()));
    }





}
